﻿using System.Collections;
using System.Collections.Generic;
using DG.Tweening;
using UnityEngine;
using UnityEngine.UI;


/// <summary>
/// 区域动画，适合按钮从区域的边缘进入，离开的动画
/// </summary>
public class UIGroupAnimate : MonoBehaviour
{

    private struct CacheState
    {
        public Vector3 localPosition;
        public Vector3 localAngles;
        public Vector3 localScale;
        public float alpha;
    }

    private Dictionary<string, CacheState> _cacheDic = new Dictionary<string, CacheState>();

    public enum AnimateType
    {
        Fade,
        MoveCenterHorizontal,
        MoveCenterVertical,
        Scale,
        MoveBottomToTop,
    }

    public AnimateType animateType = AnimateType.Fade;

    [Header("=====  进入动画配置    =====")]
    public bool isAutoStartAnimate = true;

    [Range(0, 5)]
    public float speedPopIn = 0.5f;
    public Ease easePopIn = Ease.OutSine;

    [Range(0, 2), Tooltip("播放动画前的初始值比例调整")]
    public float easeValuePopIn = 1f;


    [Header("=====  离开动画配置    =====")]

    [Range(0, 5)]
    public float speedPopOut = 0.5f;
    public Ease easePopOut = Ease.OutSine;
    [Range(0, 2), Tooltip("播放动画前的初始值比例调整")]
    public float easeValuePopOut = 1f;

    /// <summary>
    /// 执行动画的延迟间隔时间 (按间隔时间顺序出来)
    /// </summary>
    [Header("====  动画延迟偏移时间 ====")]
    public float offsetDelayTime = 0.1f;

    public float delayTime = 0f;

    private void Start()
    {
        //缓存界面初始状态

        if (this.isAutoStartAnimate)
        {
            this.PopStart();
        }

    }


    private void OnDestroy()
    {
        this._cacheDic.Clear();
    }

    private void CacheAllChildrenInfo()
    {
        foreach (Transform child in transform)
        {
            SaveCacheData(child);
            child.gameObject.SetActive(false);
        }

    }

    private void SaveCacheData(Transform trans)
    {
        string item = trans.GetInstanceID().ToString();
        if (!_cacheDic.ContainsKey(item))
        {
            _cacheDic.Add(item, new CacheState()
            {
                localPosition = trans.localPosition,
                localAngles = trans.localEulerAngles,
                localScale = trans.localScale
            });
        }
    }

    private CacheState GetCacheData(Transform trans)
    {
        string item = trans.GetInstanceID().ToString();
        CacheState cache = default;
        if (_cacheDic.ContainsKey(item))
        {
            cache = _cacheDic[item];
        }
        return cache;
    }

    public void AnimateEnter(Transform transform, AnimateType animateType, Ease ease, float power, float speed, float delay = 0, float offsetDelayTime = 0)
    {
        int index = 0;
        CacheState cacheState = default;

        switch (animateType)
        {
            case AnimateType.Fade:
                index = 0;
                foreach (Transform child in transform)
                {
                    child.gameObject.SetActive(true);
                    var image = child.GetComponent<Image>();
                    if (image)
                    {
                        image.color = new Color(image.color.r, image.color.g, image.color.b, 1 - power);
                        image.DOFade(1.0f, speed).SetDelay(offsetDelayTime * index + delay).SetEase(ease);
                        index++;
                    }
                    else
                    {
                        var text = child.GetComponent<Text>();
                        if (text)
                        {
                            text.color = new Color(text.color.r, text.color.g, text.color.b, 1 - power);
                            text.DOFade(1.0f, speed).SetDelay(offsetDelayTime * index + delay).SetEase(ease);
                            index++;
                        }

                    }
                }
                break;
            case AnimateType.MoveCenterHorizontal:
                index = 0;
                foreach (Transform child in transform)
                {
                    child.gameObject.SetActive(true);
                    cacheState = GetCacheData(child);
                    bool left = child.transform.position.x < transform.position.x;
                    var size = child.GetComponent<RectTransform>().sizeDelta;
                    var originPos = cacheState.localPosition;
                    var startPos = originPos + new Vector3(left ? -size.x : size.x, 0) * power;
                    child.transform.localPosition = startPos;
                    child.transform.DOLocalMove(originPos, speed).SetDelay(offsetDelayTime * index + delay).SetEase(ease);

                    index++;
                }
                break;
            case AnimateType.MoveCenterVertical:
                index = 0;
                foreach (Transform child in transform)
                {
                    child.gameObject.SetActive(true);
                    cacheState = GetCacheData(child);
                    bool up = child.transform.position.y < transform.position.y;
                    var size = child.GetComponent<RectTransform>().sizeDelta;
                    var originPos = cacheState.localPosition;
                    var startPos = originPos + new Vector3(0, up ? size.y : -size.y) * power;
                    child.transform.localPosition = startPos;
                    child.transform.DOLocalMove(originPos, speed).SetDelay(offsetDelayTime * index + delay).SetEase(ease);
                    index++;
                }
                break;
            case AnimateType.Scale:
                index = 0;
                foreach (Transform child in transform)
                {
                    child.gameObject.SetActive(true);
                    cacheState = GetCacheData(child);
                    var originScale = cacheState.localScale;
                    var fromScale = 1 - Mathf.Clamp(power, 0, 1);
                    child.transform.localScale = Vector3.one * fromScale;
                    child.transform.DOScale(originScale, speed).SetDelay(offsetDelayTime * index + delay).SetEase(ease);
                    index++;
                }
                break;
            case AnimateType.MoveBottomToTop:
                index = 0;
                foreach (Transform child in transform)
                {
                    child.gameObject.SetActive(true);
                    var group = child.GetComponent<CanvasGroup>();
                    if (group == null)
                    {
                        group = child.gameObject.AddComponent<CanvasGroup>();
                    }
                    group.alpha = 0;
                    cacheState = GetCacheData(child);
                    var originPos = cacheState.localPosition;
                    var startPos = originPos + new Vector3(0, -400) * power;
                    child.transform.localPosition = startPos;
                    child.transform.DOLocalMove(originPos, speed).SetDelay(offsetDelayTime * index + delay).SetEase(ease);
                    group.DOFade(1.0f, speed).SetDelay(offsetDelayTime * index + delay).SetEase(ease);
                    index++;
                }
                break;

        }
    }


    public void AnimateExit(Transform transform, AnimateType animateType, Ease ease, float power, float speed, float delay, float offsetDelayTime = 0)
    {
        int index = transform.childCount;
        // CacheState cacheState = default;

        switch (animateType)
        {
            case AnimateType.Fade:
                foreach (Transform child in transform)
                {
                    var image = child.GetComponent<Image>();
                    if (image)
                    {
                        image.DOFade(0f, speed).SetDelay(offsetDelayTime * index + delay).SetEase(ease);
                        index--;
                    }
                    else
                    {
                        var text = child.GetComponent<Text>();
                        if (text)
                        {
                            text.DOFade(0f, speed).SetDelay(offsetDelayTime * index + delay).SetEase(ease);
                            index--;
                        }

                    }
                }
                break;
            case AnimateType.MoveCenterHorizontal:
                foreach (Transform child in transform)
                {
                    bool left = child.transform.position.x < transform.position.x;
                    var size = child.GetComponent<RectTransform>().sizeDelta;
                    var offsetPos = new Vector3(left ? -size.x : size.x, 0) * power;
                    var targetPos = child.transform.localPosition + offsetPos;
                    child.transform.DOLocalMove(targetPos, speed).SetDelay(offsetDelayTime * index + delay).SetEase(ease);
                    index--;
                }
                break;
            case AnimateType.MoveCenterVertical:
                foreach (Transform child in transform)
                {
                    bool up = child.transform.position.y < transform.position.y;
                    var size = child.GetComponent<RectTransform>().sizeDelta;
                    var offsetPos = new Vector3(0, up ? size.y : -size.y) * power;
                    var targetPos = child.transform.localPosition - offsetPos;
                    child.transform.DOLocalMove(targetPos, speed).SetDelay(offsetDelayTime * index + delay).SetEase(ease);
                    index--;
                }
                break;
            case AnimateType.Scale:
                foreach (Transform child in transform)
                {
                    var targetScale = 1 - Mathf.Clamp(power, 0, 1);
                    child.transform.DOScale(targetScale, speed).SetDelay(offsetDelayTime * index + delay).SetEase(ease);
                    index--;
                }
                break;
            case AnimateType.MoveBottomToTop:
                foreach (Transform child in transform)
                {
                    child.gameObject.SetActive(true);
                    var group = child.GetComponent<CanvasGroup>();
                    if (group == null)
                    {
                        group = child.gameObject.AddComponent<CanvasGroup>();
                    }
                    var targetPos = child.transform.localPosition + new Vector3(0, -400) * power;
                    child.transform.DOLocalMove(targetPos, speed).SetDelay(offsetDelayTime * index + delay).SetEase(ease);
                    group.DOFade(0f, speed).SetDelay(offsetDelayTime * index + delay).SetEase(ease);
                    index--;
                }
                break;

        }
    }

    [EditorButton]
    [ContextMenu("测试进入动画")]
    public void PopStart()
    {
        if (gameObject.activeInHierarchy)
        {
            this.CacheAllChildrenInfo();
            AnimateEnter(this.transform, this.animateType, this.easePopIn, this.easeValuePopIn, this.speedPopIn, delayTime, offsetDelayTime);
        }
        {
            gameObject.SetActive(true);
            this.CacheAllChildrenInfo();
            AnimateEnter(this.transform, this.animateType, this.easePopIn, this.easeValuePopIn, this.speedPopIn, delayTime, offsetDelayTime);

        }
    }

    [EditorButton]
    [ContextMenu("测试离开动画")]
    public void PopEnd()
    {
        AnimateExit(this.transform, this.animateType, this.easePopOut, this.easeValuePopOut, this.speedPopOut, delayTime, offsetDelayTime);
    }


}
